"""
Total RNA Sequence Data Analysis
"""

import logging
import os
import sys
import time
import traceback
from argparse import ArgumentParser

PROJECT_DIR = os.path.abspath(os.path.join(os.getcwd(), "./"))
if PROJECT_DIR not in sys.path:
    sys.path.append(PROJECT_DIR)

from common import execute, generate_command, get_cores, get_samples, load_json


class RNASeq:
    def __init__(self, param, logger):
        self.config_data = param
        self.start_at = time.perf_counter()
        self.logger = logger
        self.dirs_name = ["1_clean", "2_alignment", "3_qualitative"]
        self.samples = get_samples(
            param["step1"]["raw_reads_directory"], param["step1"]["suffix_len"]
        )
        self.cores = get_cores()
        print(self.samples, self.cores)

    def step1(self):
        for dir_name in self.dirs_name:
            os.makedirs(f"{self.config_data['output']}/{dir_name}", exist_ok=True)

    def write_log(self, log_item: dict):
        func = getattr(self.logger, log_item["type"])
        func(log_item["context"])

    def sequential(self, commands):
        for cmd in commands:
            exec_log = execute(cmd)
            self.write_log(exec_log)

    def step2(self):
        """
        Data quality control
        :return:
        """
        commands = [
            generate_command(
                {
                    "input_dir": self.config_data["step1"]["raw_reads_directory"],
                    "output_dir": f"{self.config_data['output']}/1_clean",
                    "commands": self.config_data["step2"]["cmd"],
                    "options": self.config_data["step2"]["options"],
                    "cores": self.cores,
                    "sample_name": name,
                    "file_names": file_names,
                },
                "step2",
            )
            for name, file_names in self.samples.items()
        ]
        self.sequential(commands)

    def step3(self):
        """
        Alignment to the reference genome
        :return:
        """
        commands = [
            generate_command(
                {
                    "input_dir": f"{self.config_data['output']}/1_clean",
                    "output_dir": f"{self.config_data['output']}/2_alignment",
                    "commands": self.config_data["step3"]["cmd"],
                    "options": self.config_data["step3"]["options"],
                    "cores": self.cores,
                    "sample_name": name,
                    "hisat2_index_directory": self.config_data["step1"][
                        "hisat2_index_directory"
                    ],
                },
                "step3",
            )
            for name, file_names in self.samples.items()
        ]
        self.sequential(commands)

    def step4(self):
        """
        Quantitative analysis of the expression levels
        :return:
        """
        commands = [
            generate_command(
                {
                    "commands": self.config_data["step4"]["cmd"],
                    "input_dir": f"{self.config_data['output']}/2_alignment",
                    "output_dir": f"{self.config_data['output']}/3_qualitative",
                    "options": self.config_data["step4"]["options"],
                    "sample_name": name,
                    "cores": self.cores,
                    "reference_annotation": self.config_data["step1"][
                        "reference_annotation"
                    ],
                },
                "step4",
            )
            for name, file_names in self.samples.items()
        ]
        self.sequential(commands)

    def runs(self):
        self.step1()
        self.step2()
        self.step3()
        self.step4()


if __name__ == "__main__":
    parser = ArgumentParser(description="")
    parser.add_argument(
        "-c", "--config", type=str, required=True, help=" specify config file "
    )
    args = parser.parse_args()
    config_data = load_json(args.config)

    log_name = int(time.time())
    log_file_path = f"{config_data['output']}/{log_name}.log"
    logging.basicConfig(
        filename=log_file_path,
        filemode="a",
        level=logging.DEBUG,
        format="%(asctime)s - %(name)s - %(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s",
    )
    logging.info("The program begins!")
    try:
        RNASeq(config_data, logging).runs()

    except Exception:
        exc_type, exc_value, exc_traceback_obj = sys.exc_info()
        traceback.print_exception(
            exc_type,
            exc_value,
            exc_traceback_obj,
            file=open(log_file_path, "a", encoding="utf-8"),
        )

        sys.exit(exc_type)

    finally:
        logging.info("The program complete!")
